package org.sas.example.authentication.adaptive;

import org.sas.example.authentication.wechat.WechatCodeGrantRequestEntityConverter;
import org.sas.example.authentication.wechat.WechatMapAccessTokenResponseConverter;
import org.sas.example.constant.SecurityConstants;
import org.springframework.http.MediaType;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.Collections;

/**
 * 兼容支持“text/plain”类型数据响应处理类
 *
 * @author LiJY
 * @date 2024/07/11
 */
@Component
public class BasicAccessTokenResponseClient implements OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> {

    /**
     * 默认使用DefaultAuthorizationCodeTokenResponseClient来获取token
     */
    private final DefaultAuthorizationCodeTokenResponseClient tokenResponseClient = new DefaultAuthorizationCodeTokenResponseClient();

    /**
     * 初始化时设置 DefaultAuthorizationCodeTokenResponseClient 支持的响应数据格式
     * 自定义 RestTemplate，适配微信登录获取token
     */
    public BasicAccessTokenResponseClient() {
        tokenResponseClient.setRequestEntityConverter(new WechatCodeGrantRequestEntityConverter());
        OAuth2AccessTokenResponseHttpMessageConverter messageConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
        // 微信返回的content-type 是 text-plain
        messageConverter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON,
                MediaType.TEXT_PLAIN,
                new MediaType("application", "*+json")));
        messageConverter.setAccessTokenResponseConverter(new WechatMapAccessTokenResponseConverter());

        // 初始化RestTemplate
        RestTemplate restTemplate = new RestTemplate(Arrays.asList(new FormHttpMessageConverter(), messageConverter));
        restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
        tokenResponseClient.setRestOperations(restTemplate);
    }

    /**
     * 获取token响应
     *
     * @param authorizationGrantRequest 授权授予请求
     * @return {@link OAuth2AccessTokenResponse}
     */
    @Override
    public OAuth2AccessTokenResponse getTokenResponse(OAuth2AuthorizationCodeGrantRequest authorizationGrantRequest) {
        String registrationId = authorizationGrantRequest.getClientRegistration().getRegistrationId();
        if (SecurityConstants.THIRD_LOGIN_WORK_WECHAT.equals(registrationId)) {
            // 缓存获取token 如果获取不到再请求，并放入缓存，企业微信的token不允许频繁获取
            OAuth2AccessTokenResponse tokenResponse = tokenResponseClient.getTokenResponse(authorizationGrantRequest);
            String code = authorizationGrantRequest.getAuthorizationExchange()
                    .getAuthorizationResponse()
                    .getCode();
            return OAuth2AccessTokenResponse.withResponse(tokenResponse)
                    .additionalParameters(Collections.singletonMap(OAuth2ParameterNames.CODE, code))
                    .build();
        }
        return tokenResponseClient.getTokenResponse(authorizationGrantRequest);
    }
}
